Skip to content

refactor(spec)!: remove manifest.loading — an inert loading block whose sandbox isolated nothing (#4914) - #7067

Merged
os-zhuang merged 5 commits into
mainfrom
claude/issue-4914-plugin-loading-retirement
Aug 9, 2026
Merged

refactor(spec)!: remove manifest.loading — an inert loading block whose sandbox isolated nothing (#4914)#7067
os-zhuang merged 5 commits into
mainfrom
claude/issue-4914-plugin-loading-retirement

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes #4914

Retires the plugin manifest's whole loading block under ADR-0049
enforce-or-remove. The block declared a complete plugin loading policy —
strategy, preload, codeSplitting, dynamicImport, initialization,
dependencyResolution, hotReload, caching, sandboxing, monitoring — and
nothing read any of it. Authoring it parsed cleanly, entered the manifest, and
configured nothing.

loading.sandboxing is why this outranked ordinary inert-key cleanup. It
declared isolationLevel of process / vm / iframe / web-worker, IPC
transports and an allowedServices ACL, and applied none of it. An author —
very often an AI (ADR-0033) — read that vocabulary as proof the platform
isolates plugins, wrote the config, and got a clean parse and zero isolation. An
inert security control is worse than an absent one, because it is believed.

Maintainer ruling (2026-08-04) — quoted verbatim, untranslated

  1. 方向:remove(manifest.loading 整块 + PluginHotReloadSchema / PluginSandboxingSchema,走 spec-property-retirement 全套:tombstone / D3 registry / baselines / pin test / changeset,同步改写 PLUGIN_STANDARDS §5.1/§5.2/§5.4)。理由采纳本单两轴分析:一段 parse 得过、永不生效的沙箱配置,在安全语义上比别处的 inert 键更危险 —— AI 作者会真的以为自己加了隔离。
  2. hot-reload 双源收敛:保留有实现体(HotReloadManager)的 HotReloadConfigSchema 一侧作为将来 enforce 的起点;退役 PluginHotReloadSchema
  3. 硬前置:动手前必须补 cloud / objectui 两仓的裸名反查(带对照验证,按 refactor(spec)!: 退役 plugin-runtime 家族五个 schema —— 无任何 runtime 实现的「Dynamic Loading」词表 (#4834, ADR-0049) #4878 的做法)—— 反查不干净则回到本单重议。

The hard prerequisite: three-repo bare-name reverse lookup

Both halves clean. Each probe ran with a control probe proving the scan saw the
tree, per the #4878 method.

objectstack (this repo) — every hit for the eleven schema names and
manifest.loading lives inside packages/spec itself: the declarations, the
module's own unit tests, the manifest.zod.ts embed, one type-alias pin, and
generated artifacts. Zero readers in packages/core, packages/runtime,
packages/metadata.

cloud — measured by the spec seat against cloud origin/main, fetched
2026-08-09 ~06:50Z (issue comment):

  • Probe 1 PluginHotReloadSchema|PluginSandboxingSchema|manifest\.loading0 hits
  • Probe 2 ["'](hotReload|sandboxing)["']0 hits
  • Control @objectstack/spec — hits across many files, so the zeros are real

objectui — measured in this lap against objectui origin/main =
2c632d94ed94b9dcd14aec122452d1769fd64b49:

  • Probe 1 PluginHotReloadSchema|PluginSandboxingSchema|manifest\.loading0 hits
  • Probe 2 ["'](hotReload|sandboxing)["']0 hits
  • Control A PackagesPage — hits across many source files
  • Control C ["'](contributes|capabilities)["'] (same quoted-key regex form as probe 2) — hits in plugin-chatbot/src/useAgents.ts and vscode-extension/package.json, so the probe-2 form matches real quoted keys and its zero is real
  • A looser probe (hotReload|sandboxing|isolationLevel|allowedServices) returned exactly one hit — packages/app-shell/src/views/metadata-admin/PackagesPage.tsx:77, a prose comment listing manifest key names in a doc block. Not a consumer, and it refers to PackageManifest rather than manifest.loading.sandboxing. I checked whether the spec's cloud PackageManifest has its own top-level sandboxing: it does not.

Route: tombstone, not plain deletion

ManifestSchema is not .strict() (it closes with no .strict()), so deleting
the key would let zod strip it in silence — trading an inert declaration for an
invisible one, the #3726 / #3733 shape (ADR-0104). So Manifest.loading is a
retiredKey() tombstone, audible through tsc (input type never) and through
the parse, which raises the prescription itself.

This differs from the neighbouring #3896 / #4834 precedents, which plain-deleted,
and the difference is measured rather than assumed: those shapes were parsed by
nothing, so a prescription could never be received. A manifest is parsed by
real code — packages/objectql/src/registry.ts:1633 and
packages/cli/src/commands/plugin/build.ts:111 — so the tombstone reaches an
author.

The eleven value schemas the key carried are orphaned by its removal and go with
it (playbook §4; an exported schema with no consumer is read as a capability,
#3950). PluginLoadingEvent and PluginLoadingState deliberately survive: same
module, but never embedded in the config block, not authorable, still emitted.
Module adjacency is not evidence.

Why D3-only, no D2 conversion

The dispatch asked for this to be evaluated explicitly rather than copied.
Measured: the conversion chain walks a normalized stack
(mapCollection(stack, 'objects' | 'views' | …)), and applyConversionsToStoredItem
maps a metadata type onto one of those collections. A package manifest is
neither — PLURAL_TO_SINGULAR has no packages or plugins entry, so a
manifest is not a stack collection member, and stored.ts documents that a type
with no stack collection passes through unchanged. A MetadataConversion here
would be a transform with no seam that ever runs.

So the registration is a D3 SemanticMigration (plugin-manifest-loading-retired)
plus the exact-key entry, exactly as automation/ActionDescriptor:isAsync
(#6748) and the notification cursor keys (#6361) did in this same major.

Is a D2 conversion needed for stored metadata anyway? No, and the reason is
worth stating because a manifest is durable (sys_packages). The at-rest read
path is Registry.validate(), which the code documents as a deliberate
diagnostic and not a gate: it catches, logs [metadata_spec_invalid], and
registers the item anyway so bad metadata is never a data outage. So an installed
package whose stored manifest still carries loading keeps working and degrades
to one log line. The enforced channel is os plugin build, which runs
ManifestSchema.safeParse with the author present and exits non-zero carrying
the prescription.

No liveness-ledger change. The ledger walks BUILTIN_METADATA_TYPE_SCHEMAS
(authorable metadata types) and the kernel manifest is not one — there is no
liveness/manifest.json and ManifestSchema is not registered — so
manifest.loading never had a row to keep or to orphan.

Hot reload: the two-source convergence (ruling §2)

PluginHotReloadSchema was the dead one of two hot-reload vocabularies, and
PLUGIN_STANDARDS.md §5.1 pointed readers at exactly that one. The surviving
side is HotReloadConfigSchema (plugin-lifecycle-advanced.zod.ts), which
HotReloadManager (packages/core/src/hot-reload.ts) actually reads. It is
KEPT.

§5.1 now points there and states its real status honestly: HotReloadManager
exists and is unit-tested, but no runtime composes one — the only
constructions are its own test and packages/core/examples/phase2-integration.ts
— so it is a foundation, not a shipped capability. Enforcing it is deliberately
left to a separate future decision and is not part of this PR.

Docs

  • §5.1 rewritten to the surviving vocabulary with its honest status; §5.2 marked REMOVED with what is actually enforced (manifest.runtime trust tier, permission declarations); §5.4 rows for Hot Reload and Plugin Isolation corrected.
  • §5.4's Dependency Resolution row also cited plugin-loading.zod.ts and would have dangled. The capability is real (resolvePluginOrder, packages/core/src/plugin-order.ts), only the schema pointer was wrong, so the row is re-pointed rather than downgraded.
  • PROTOCOL_MAP.md row rewritten; content/docs/protocol/kernel/index.mdx summary line said the plugin system ships "sandboxing", which is now false in every reading, so it names trust tiers instead.

Reverse verification — direction predicted first, then measured

Predicted before running: restoring the retired declarations turns 4 of the 5
new pins RED, and not.toHaveProperty('loading') stays GREEN, because an absent
key is absent either way.

Measured (declarations restored via git checkout origin/main --, never
git stash — the stash stack is shared across worktrees): Tests 4 failed | 1 passed (5).

Pin Predicted Measured
REJECTS an authored loading block RED RED — expected true to be false
REJECTS the sandboxing block RED RED — expected true to be false
REJECTS hotReload RED RED — expected true to be false
does not export the retired schemas RED RED — PluginLoadingConfigSchema must not be exported
parses cleanly, no loading property GREEN GREEN

A note on the rejection-envelope floor (ADR-0112 / #6142)

The dispatch set code + status as the floor for a rejection-class case. That
envelope is the API error surface — ApiErrorSchema, the ERROR_CODE_LEDGER
vocabulary, an HTTP status — and a schema tombstone does not raise one. Measured,
not assumed: a retiredKey refusal raises a ZodError whose issue carries
code and path and has no status field at all.

Asserting a status here would be a fabrication that reads as verification, so
the pins assert the strongest set this surface really has — refusal, the issue
code, the path naming which key was refused, and the prescription text
(#5240, wording-as-contract). That still delivers what #6142 is after: the pins
go red if the refusal moves to the wrong key, loses its code, or stops carrying
the fix, none of which a bare toThrow() can see.

Registries, recounted from the file after the merge lap (#6526)

#7040 (#5488) appended api-runtime-create-withdrawn to step17.semantic while
this branch appended plugin-manifest-loading-retired. Purely additive conflict,
union-keep, both retained. Recounted from the merged file:

Ratchets fired in sequence, each answered deliberately

Both are the self-proving signal the playbook describes, and the readings are the
evidence the removal is real rather than a silent unpublish:

  1. json-schema.manifest/ ratchet (gen:schema silently drops PageTabsProps since #2967 — references regen would delete real docs #2978 / json-schema.manifest.json 的「deliberate removal」删行仍是纪律而非门禁 —— #4650 的同类洞,上移一层(整 schema 级) #4725) named exactly the 11 defs that stopped being emitted — matching the RETIRED_DEFS_BY_MAJOR registration one-for-one. Manifest keys deleted deliberately (11 deletions, 0 insertions).
  2. authorable-surface/ deletion gate (authorable-surface 的 tombstone 门禁可被手编基线绕过 —— 删掉基线行就删掉了证据(#4638 / #4643 已两次这样过绿) #4650) then named 67 authorable keys under those defs. Deleted deliberately, adjudicated by route 3 (whole def no longer emitted). kernel/Manifest:loading correctly flipped to [RETIRED] rather than vanishing.

Counts: authorable surface loses 67 keys and gains one [RETIRED] marker.

Verification

  • pnpm --filter @objectstack/spec build — green (after both ratchets were answered)
  • pnpm --filter @objectstack/spec test351 files / 9081 tests / 0 failed
  • pnpm --filter @objectstack/spec exec tsc --noEmit — clean
  • All 36 gates enumerated from .github/workflows/lint.yml lint job — PASS
  • 16 spec gates from the typecheck job — PASS, including the three with no generator (check:liveness, check:empty-state, check:skill-examples)
  • node scripts/check-adr-0087-registration.mjs --base origin/main — PASS: registered plugin-manifest-loading-retired (new here)
  • Two real reds found and fixed en route: the type-alias-convention.pin.test.ts count 824 to 823 (Iso441 pinned PluginLoadingStrategySchema; recorded in that file's own receipt style) and a stale gen:strictness-ledger artifact
  • check:i18n / check:i18n-coverage / check:app-nav-i18n are prerequisite-blocked locally in a fresh worktree (they need the built CLI and say "nothing was checked"); no *.form.ts input or translation key touches this surface, and CI builds the closure

Generated by Claude Code

claude added 4 commits August 9, 2026 09:56
…hose sandbox isolated nothing (#4914)

ADR-0049 enforce-or-remove; maintainer ruling 2026-08-04. The whole
`manifest.loading` block (strategy / preload / codeSplitting / dynamicImport /
initialization / dependencyResolution / hotReload / caching / sandboxing /
monitoring) had zero runtime readers in objectstack, cloud and objectui — every
reference lived inside packages/spec itself.

`loading.sandboxing` is why this outranked ordinary inert-key cleanup: it
declared process/vm/iframe/web-worker isolation, IPC transports and an
`allowedServices` ACL and applied none of it. An inert security control is
worse than an absent one, because it is believed (ADR-0033).

Hot reload converges on the surviving vocabulary: `HotReloadConfigSchema`
(read by `HotReloadManager`) is KEPT, unenforced, as the starting point for a
separate future decision.

- `Manifest.loading` → `retiredKey()` tombstone (ManifestSchema is not strict,
  so a plain deletion would silently strip it)
- 11 whole defs unpublished, registered in RETIRED_DEFS_BY_MAJOR[17]
- `kernel/Manifest:loading` in RETIRED_KEYS_BY_MAJOR[17] + D3 SemanticMigration
  `plugin-manifest-loading-retired` (no D2: a manifest is not a stack collection)
- pin tests, changeset, PLUGIN_STANDARDS §5.1/§5.2/§5.4, PROTOCOL_MAP, baselines

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PiRUoQkTSBBmpyXBY3cVn2
#7040 (#5488) appended `api-runtime-create-withdrawn` to step17.semantic while
this branch appended `plugin-manifest-loading-retired`; the conflict was purely
additive and BOTH are kept. Recounted from the file (#6526):
RETIRED_KEYS_BY_MAJOR[17] = 12 entries, RETIRED_DEFS_BY_MAJOR[17] = 45 —
every sibling's registrations survive. Generated artifacts regenerated from the
merged tree.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PiRUoQkTSBBmpyXBY3cVn2
@vercel

vercel Bot commented Aug 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 9, 2026 7:05pm

Request Review

…ns, regen from the merged tree

Second merge lap (the first was left mid-conflict by an external cancellation and
was aborted rather than completed against a stale base — main had moved 17 commits
past its MERGE_HEAD).

Source conflict, one file:
- `packages/spec/src/migrations/registry.ts` — purely additive. #6815 appended
  `data/AggregationNode:distinct` to `RETIRED_KEYS_BY_MAJOR[17]` while this branch
  appended `kernel/Manifest:loading`. Union-keep, both retained (#6526).

Generated artifacts regenerated from the merged tree, never hand-merged:
`spec-changes.json`, `protocol-upgrade-guide.md`, `authorable-surface/`,
`json-schema.manifest/`, `authorable-defaults/`, `api-surface/`,
`export-origins/` (new in the Type Check job via #7090), `content/docs/references/`,
the strictness-ledger counts.

Both ratchets re-fired on the merged inputs and were re-answered: the
json-schema.manifest deletion gate accepted the 11 declared def removals, and the
authorable-surface deletion gate deferred its 10 def-level deletions (67 key lines)
to that gate by route 3.
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec.

106 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/spec)
  • content/docs/automation/approvals.mdx (via @objectstack/spec)
  • content/docs/automation/connectors.mdx (via @objectstack/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via @objectstack/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/cli.mdx (via @objectstack/spec)
  • content/docs/deployment/tenancy-modes.mdx (via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via @objectstack/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/data-service.mdx (via @objectstack/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/examples.mdx (via @objectstack/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via @objectstack/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via @objectstack/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/spec)
  • content/docs/permissions/authorization.mdx (via @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/rls.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/spec)
  • content/docs/permissions/system-context.mdx (via packages/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/http-protocol.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/apps.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/field-grouping-and-order.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)
  • content/docs/ui/translations.mdx (via @objectstack/spec)
  • content/docs/ui/views.mdx (via @objectstack/spec)

7 release-owned page(s) also reference the affected code. These are read-only:

  • content/docs/releases/implementation-status.mdx (via @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v16.mdx (via @objectstack/spec)
  • content/docs/releases/v17.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@github-actions github-actions Bot added size/xl documentation Improvements or additions to documentation tests tooling labels Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

Finishing lap complete — merge lap over current main, artifacts regenerated, CI converged green. Adoption dev under the PM's finisher claim; the implementation above stands as-is and was not re-litigated. New head f3c28d21b.

Merge lap

The branch was found mid-merge: the externally-cancelled dev had left a MERGE_HEAD at 2c7e62d5f with packages/spec/src/migrations/registry.ts still UU. That base was 17 commits stale, so the partial merge was aborted rather than completed (HEAD was the pushed PR head, so nothing was at risk) and the lap was redone against f5a9bc2f3.

One source conflict, purely additive: #6815 appended data/AggregationNode:distinct to RETIRED_KEYS_BY_MAJOR[17] while this branch appended kernel/Manifest:loading. Union-keep, both retained (#6526).

Registries recounted from the merged file (#6526)

The body's counts above were measured against the earlier base and have moved:

Registry Body Now Delta
RETIRED_KEYS_BY_MAJOR[17] 12 13 +data/AggregationNode:distinct (#6815)
RETIRED_DEFS_BY_MAJOR[17] 45 45 unchanged — #6815 registered no defs
step17.semantic 44 45 +aggregation-node-distinct-retired (#6815)

Sibling-survival asserted, entry by entry. All 11 pre-existing key entries survive (3 transform, 3 record-picker + ui/PageCardProps:body, ui/PageTabsProps:type, automation/ActionDescriptor:isAsync, 2 notification cursor), plus this branch's kernel/Manifest:loading and #6815's. In step17.semantic both plugin-manifest-loading-retired (43) and #7040's api-runtime-create-withdrawn (44) survive alongside the new 45th.

Regenerated from the merged tree, never hand-merged

spec-changes.json, protocol-upgrade-guide.md, authorable-surface/, json-schema.manifest/, authorable-defaults/, api-surface/, content/docs/references/, the strictness-ledger counts — and export-origins/, which #7090 added to the required Type Check job after this branch was cut.

That last one is the notable new surface: this PR retires exported schemas, so its shards necessarily change. gen:export-origins reported 4959 exports across 16 entry points — 1 shard(s) rewritten (the kernel shard). Verified rather than assumed — all 11 retired schema names return 0 hits across all 16 shards, while the control ManifestSchema still hits 4 times and the deliberate survivors PluginLoadingEvent / PluginLoadingState hit 5. The deletion was regenerated, not hand-edited.

Ratchets re-fired on the merged inputs and re-answered

  • json-schema.manifest/ deletion gate — accepted the 11 declared def removals, one-for-one against RETIRED_DEFS_BY_MAJOR.
  • authorable-surface/ deletion gate — 10 def-level deletions totalling 67 key lines, all adjudicated by route 3 (def no longer emitted), deferred to the manifest gate above. Same 67 as the body reports, now grouped per def.

Reverse lookup re-run against the merged tree

The 17 newly-merged commits could in principle have introduced a reader. They did not: PluginHotReloadSchema|PluginSandboxingSchema|PluginLoadingConfigSchema|manifest.loading outside packages/spec returns 0 hits, with a control (ManifestSchema) hitting 5 files including both parse sites the body names.

Verification

  • pnpm --filter @objectstack/spec test356 files / 9242 tests / 0 failed (up from 351/9081; the merge brought new tests)
  • The 5 retirement pins run directly — Test Files 1 passed (1) / Tests 5 passed (5)
  • tsc --noEmit — clean; 45 of 46 local gates green across both lint.yml job lists
  • Two gates are prerequisite-blocked in a fresh worktree and neither is a real red, same class as the check:i18n note in the body:

CI — full convergence on f3c28d21b

All 26 check runs completed: 25 success, 1 skipped (Console Pin Gate), zero failures. Read by job conclusion, not by aggregate status:

Job Conclusion
ESLint (carries the family gates) success
TypeScript Type Check (carries check:export-origins) success
Test Core 1/3, 2/3, 3/3 success
Build Core / Build Docs / Dogfood Regression 1-3 success
Check Changeset / Spec property liveness / ADR maintainer approval success

This PR touches no docs/adr/** pathPROTOCOL_MAP.md and content/docs/protocol/kernel/index.mdx are not docs/adr, and the ADR maintainer approval gate passed accordingly.

Left as a draft, auto-merge deliberately not enabled and the merge queue not entered — the PM lands.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/xl tests tooling

Projects

None yet

2 participants